#ifndef OPENNAVSEARCHSERVICEPROVIDER_H_
#define OPENNAVSEARCHSERVICEPROVIDER_H_

#include <FBase.h>
#include "Opennav.h"
#include "OpennavMap.h"

class OpennavSearchServiceProvider;

enum OpennavSearchRequestType {
	SEARCH_COUNTRY,
	SEARCH_CITY,
	SEARCH_ROAD
};

class IOpennavSearchRequest {
public:
	virtual OpennavSearchRequestType GetRequestType() const = 0;
};

class OpennavSearchCountryRequest : public IOpennavSearchRequest {
public:
	OpennavSearchCountryRequest(const Osp::Base::String& name);
	const Osp::Base::String& GetSearchString() const;
	OpennavSearchRequestType GetRequestType() const;

private:
	const Osp::Base::String __searchString;
};

class OpennavSearchCityRequest : public IOpennavSearchRequest {
public:
	OpennavSearchCityRequest(const Osp::Base::String& name, int countryId);
	const Osp::Base::String& GetSearchString() const;
	int GetCountryId() const;
	OpennavSearchRequestType GetRequestType() const;

private:
	const Osp::Base::String __searchString;
	int __countryId;
};

class OpennavSearchRoadRequest : public IOpennavSearchRequest {
public:
	OpennavSearchRoadRequest(const Osp::Base::String& name, int cityId);
	const Osp::Base::String& GetSearchString() const;
	int GetCityId() const;
	OpennavSearchRequestType GetRequestType() const;

private:
	const Osp::Base::String __searchString;
	int __cityId;
};

class IOpennavSearchResult {
public:
	virtual OpennavSearchRequestType GetRequestType() const = 0;
};

class OpennavSearchCountryResult : public IOpennavSearchResult {
public:
	OpennavSearchCountryResult(OpennavMap* map, opennav::SearchCountryResult& r);
	void GetResult(int n, opennav::Country& country);
	int GetCount() const;
	OpennavSearchRequestType GetRequestType() const;

private:
	OpennavMap* __pMap;
	opennav::SearchCountryResult __result;
};

class OpennavSearchCityResult : public IOpennavSearchResult {
public:
	OpennavSearchCityResult(OpennavMap* map, opennav::SearchCityResult& r);
	void GetResult(int n, opennav::City& city);
	int GetCount() const;
	OpennavSearchRequestType GetRequestType() const;

private:
	OpennavMap* __pMap;
	opennav::SearchCityResult __result;
};

class OpennavSearchRoadResult : public IOpennavSearchResult {
public:
	OpennavSearchRoadResult(OpennavMap* map, opennav::SearchRoadResult& r);
	void GetResult(int n, opennav::Road& road);
	int GetCount() const;
	OpennavSearchRequestType GetRequestType() const;

private:
	OpennavMap* __pMap;
	opennav::SearchRoadResult __result;
};

class IOpennavSearchServiceListener {
public:
	virtual void OnGeocodingRequestResultReceived(IOpennavSearchResult* result) = 0;
};

class OpennavSearchServiceProvider : private Osp::Base::Runtime::IRunnable {
public:
	OpennavSearchServiceProvider();
	~OpennavSearchServiceProvider();
	result Construct(OpennavMap* map);
	void Search(const IOpennavSearchRequest& request, IOpennavSearchServiceListener& listener);

public:
	Osp::Base::Object* Run(void);

private:
	OpennavMap* __pMap;
	Osp::Base::Runtime::Thread* __pSearchWorker;
	Osp::Base::Runtime::Mutex* __pLock;
	bool __kill;
	IOpennavSearchRequest* __pRequest;
	IOpennavSearchServiceListener* __pRequestListener;
};


#endif /* OPENNAVSEARCHSERVICEPROVIDER_H_ */
